<?php
/**
 *（Logic） Amazon订单
 */
namespace App\Logic\Amazon\Api;

use App\Models\Amazon\AmazonOrder;
use App\Models\Amazon\AmazonOrderAddress;
use App\Models\Amazon\AmazonOrderCondition;
use App\Models\Amazon\AmazonOrderConditionBak;
use App\Models\Amazon\AmazonOrderItem;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use SellingPartnerApi\Api\OrdersV0Api as OrdersApi;
use SellingPartnerApi\Model\OrdersV0\Order;
use SellingPartnerApi\Model\OrdersV0\OrderItem;
use Exception;
use SellingPartnerApi\Model\OrdersV0\OrdersList;

class Orders
{
    const GRAB_ORDERS_INTERVAL = 600;

    const GRAB_ZONE_INTERVAL = 3600 * 8;

    /**
     * 返回您在指定时间段内所创建或更新的订单。补单用
     * @param $config
     * @param $account
     * @param null $last_updated_after
     * @param null $last_updated_before
     * @param int $times
     * @return bool
     */
    public static function apiGetOrdersBak($config, $account, $last_updated_after = null, $last_updated_before = null, int $times = 1): bool
    {
        if(!$account)return false;
        if(!$last_updated_after){
            $last_updated_after = AmazonOrderConditionBak::getNextStartTime($account->id);
            if(!$last_updated_after)return false;
        }
        if(!$last_updated_before){
            $last_updated_before = self::_getLastUpdatedBefore($last_updated_after,$times);
        }
        if(strtotime($last_updated_after) >= strtotime($last_updated_before))return false;
        $marketplace_ids = $account->account_country->pluck('marketplace_id')->toArray();
        $apiInstance = new OrdersApi($config);
        $ordersList = self::_getOrders($apiInstance,$marketplace_ids,$last_updated_after,$last_updated_before);
        if($ordersList){
            try{
                $orders = $ordersList->getOrders();
                DB::connection('mysql_amazon')->beginTransaction();
                foreach ($orders as $order){
                    self::_extractAmazonOrder($order,$apiInstance,$account->id);
                    sleep(1);
                }
                $last_updated_before = $ordersList->getLastUpdatedBefore();
                AmazonOrderConditionBak::upNextStartTime($account->id,$last_updated_before);
                $next_token = $ordersList->getNextToken();
                self::_getOrdersByNextToken($apiInstance,$account->id,$marketplace_ids,$last_updated_after,$last_updated_before,$next_token);
                DB::connection('mysql_amazon')->commit();
            }catch (\Exception $e){
                DB::connection('mysql_amazon')->rollBack();
                Log::log('error',$e->getMessage().'Trace:'.$e->getTraceAsString());
                return false;
            }
        }
        return true;
    }

    /**
     * 返回您在指定时间段内所创建或更新的订单。
     * @param $config
     * @param $account
     * @param null $last_updated_after
     * @param null $last_updated_before
     * @param int $times
     * @return bool
     */
    public static function apiGetOrders($config, $account, $last_updated_after = null, $last_updated_before = null, int $times = 1): bool
    {
        if(!$account)return false;
        if(!$last_updated_after){
            $last_updated_after = AmazonOrderCondition::getNextStartTime($account->id);
        }
        if(!$last_updated_after)return false;
        if(!$last_updated_before){
            $last_updated_before = self::_getLastUpdatedBefore($last_updated_after,$times);
        }
        if(strtotime($last_updated_after) >= strtotime($last_updated_before))return false;
        $marketplace_ids = $account->account_country->pluck('marketplace_id')->toArray();
        $apiInstance = new OrdersApi($config);
        $ordersList = self::_getOrders($apiInstance,$marketplace_ids,$last_updated_after,$last_updated_before);
        if($ordersList){
            try{
                $orders = $ordersList->getOrders();
                DB::connection('mysql_amazon')->beginTransaction();
                foreach ($orders as $order){
                    self::_extractAmazonOrder($order,$apiInstance,$account->id);
                    sleep(1);
                }
                $last_updated_before = $ordersList->getLastUpdatedBefore();
                AmazonOrderCondition::upNextStartTime($account->id,$last_updated_before);
                $next_token = $ordersList->getNextToken();
                self::_getOrdersByNextToken($apiInstance,$account->id,$marketplace_ids,$last_updated_after,$last_updated_before,$next_token);
                DB::connection('mysql_amazon')->commit();
            }catch (\Exception $e){
                DB::connection('mysql_amazon')->rollBack();
                Log::log('error',$e->getMessage().'Trace:'.$e->getTraceAsString());
                return false;
            }
        }
        return true;
    }

    /**
     * 使用 next_token 参数返回下一页订单。
     * @param $apiInstance
     * @param $accountId
     * @param $marketplace_ids
     * @param $last_updated_after
     * @param $last_updated_before
     * @param $next_token
     */
    private static function _getOrdersByNextToken($apiInstance,$accountId,$marketplace_ids,$last_updated_after,$last_updated_before,$next_token){
        if($next_token){
            sleep(1);
            $ordersList = self::_getOrders($apiInstance,$marketplace_ids,$last_updated_after,$last_updated_before,null,$next_token);
            if($ordersList){
                $orders = $ordersList->getOrders();
                foreach ($orders as $order){
                    self::_extractAmazonOrder($order,$apiInstance,$accountId);
                    sleep(1);
                }
                $last_updated_before = $ordersList->getLastUpdatedBefore();
                AmazonOrderCondition::upNextStartTime($accountId,$last_updated_before);
                $next_token = $ordersList->getNextToken();
                self::_getOrdersByNextToken($apiInstance,$accountId,$marketplace_ids,$last_updated_after,$last_updated_before,$next_token);
            }
        }
    }

    /**
     * 返回您在指定OrderIDs的订单。
     * @param $config
     * @param $account
     * @param $amazon_order_ids
     * @return bool
     * @throws \Throwable
     */
    public static function apiGetOrdersViaOrderIDs($config,$account,$amazon_order_ids){
        if(!$account)return false;
        if(!$amazon_order_ids)return false;

        $marketplace_ids = $account->account_country->pluck('marketplace_id')->toArray();
        $apiInstance = new OrdersApi($config);
        $ordersList = self::_getOrders($apiInstance,$marketplace_ids,null,null,$amazon_order_ids);
        if($ordersList){
            try{
                $orders = $ordersList->getOrders();
                DB::connection('mysql_amazon')->beginTransaction();
                foreach ($orders as $order){
                    self::_extractAmazonOrder($order,$apiInstance,$account->id);
                    sleep(1);
                }
                $next_token = $ordersList->getNextToken();
                self::_getOrdersViaOrderIDsByNextToken($apiInstance,$account->id,$marketplace_ids,$amazon_order_ids,$next_token);
                DB::connection('mysql_amazon')->commit();
            }catch (\Exception $e){
                DB::connection('mysql_amazon')->rollBack();
                Log::log('error',$e->getMessage().'Trace:'.$e->getTraceAsString());
                return false;
            }
            return true;
        }
        return false;
    }

    private static function _getOrdersViaOrderIDsByNextToken($apiInstance,$accountId,$marketplace_ids,$amazon_order_ids,$next_token){
        if($next_token){
            sleep(1);
            $ordersList = self::_getOrders($apiInstance,$marketplace_ids,null,null,$amazon_order_ids,$next_token);
            if($ordersList){
                $orders = $ordersList->getOrders();
                foreach ($orders as $order){
                    self::_extractAmazonOrder($order,$apiInstance,$accountId);
                    sleep(1);
                }
                $next_token = $ordersList->getNextToken();
                self::_getOrdersViaOrderIDsByNextToken($apiInstance,$accountId,$marketplace_ids,$amazon_order_ids,$next_token);
            }
        }
    }

    /**
     * 更新Amazon-Order数据
     * @param Order $order
     * @param $apiInstance
     * @param $accountId
     * @throws \Throwable
     */
    private static function _extractAmazonOrder(Order $order,$apiInstance,$accountId){
        try{
            DB::connection('mysql_amazon')->beginTransaction();
            $amazonOrderId = $order->getAmazonOrderId();
            $amazonOrder = AmazonOrder::query()->firstOrNew(['amazon_order_id' => $amazonOrderId],['marketplace_id' => $order->getMarketplaceId()]);
            $amazonOrder->seller_order_id = $order->getSellerOrderId();
            $amazonOrder->purchase_date = gmdate('Y-m-d H:i:s',strtotime($order->getPurchaseDate()));
            $amazonOrder->sales_channel = $order->getSalesChannel();
            $amazonOrder->order_status = AmazonOrder::getOrderStatusIdByStr($order->getOrderStatus());
            $amazonOrder->save();
            $amazonOrderAddress = AmazonOrderAddress::query()->firstOrNew(['amazon_order_id' => $amazonOrderId]);
            $buyerInfo = $order->getBuyerInfo();
            if($buyerInfo){
                $amazonOrderAddress->buyer_name = $buyerInfo->getBuyerName();
                $amazonOrderAddress->buyer_email = $buyerInfo->getBuyerEmail();
            }
            $shippingAddress = $order->getShippingAddress();
            if($shippingAddress){
                $amazonOrderAddress->name = $shippingAddress->getName();
                $amazonOrderAddress->city = $shippingAddress->getCity();
                $amazonOrderAddress->state = $shippingAddress->getStateOrRegion();
                $amazonOrderAddress->postal_code = $shippingAddress->getPostalCode();
                $amazonOrderAddress->country = $shippingAddress->getCountryCode();
                $amazonOrderAddress->phone = $shippingAddress->getPhone();
            }
            $amazonOrderAddress->save();
            sleep(1);
            self::apiGetOrderItems($apiInstance,$accountId,$amazonOrderId);
            DB::connection('mysql_amazon')->commit();
        }catch (\Exception $e){
            DB::connection('mysql_amazon')->rollBack();
            Log::log('error',$e->getMessage().'Trace:'.$e->getTraceAsString());
        }
    }

    private static function _getOrders(OrdersApi $apiInstance,$marketplace_ids,$last_updated_after,$last_updated_before,$amazon_order_ids = null,$next_token = null){
        try{
            $result = $apiInstance->getOrders($marketplace_ids,
                null,
                null,
                $last_updated_after,
                $last_updated_before,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                $next_token,
                $amazon_order_ids,
                null,
                null,
                null,
                null);
        }catch (Exception $e){
            Log::log('error',$e->getMessage().'Trace:'.$e->getTraceAsString());
            return null;
        }
        return $result->getPayload();
    }

    private static function _getLastUpdatedBefore($lastUpdatedAfter,$times): bool|string
    {
        $lastUpdatedBefore = strtotime($lastUpdatedAfter) + self::GRAB_ORDERS_INTERVAL * $times;
        $lastUpdatedBeforeMax = time() - 120;
        $time = min($lastUpdatedBefore,$lastUpdatedBeforeMax);
        return getDateFormat(date('Y-m-d H:i:s',$time - self::GRAB_ZONE_INTERVAL));
    }

    //-------------------------------------OrderItems------------------------------------------------------------
    /**
     * 根据指定的 AmazonOrderId 返回订单商品。
     * @param $apiInstance
     * @param $accountId
     * @param $order_id
     */
    public static function apiGetOrderItems($apiInstance,$accountId,$order_id){
        $orderItemsList = self::_getOrderItems($apiInstance,$order_id);
        if($orderItemsList){
            $orderItems = $orderItemsList->getOrderItems();
            foreach ($orderItems as $orderItem){
                self::_extractAmazonOrderItems($orderItem,$order_id,$accountId);
            }
            $next_token = $orderItemsList->getNextToken();
            self::_getOrderItemsByNextToken($apiInstance,$accountId,$order_id,$next_token);
        }
    }

    private static function _extractAmazonOrderItems(OrderItem $orderItem,$order_id,$accountId){
        try{
            DB::connection('mysql_amazon')->beginTransaction();
            $orderItemTemp = [];
            $orderItemTemp['amazon_order_id'] = $order_id;
            $orderItemTemp['account_id'] = $accountId;
            $orderItemTemp['sku'] = $orderItem->getSellerSku();
            $orderItemTemp['asin'] = $orderItem->getAsin();
            $orderItemTemp['quantity'] = $orderItem->getQuantityOrdered() ?: 0;
            $orderItemTemp['quantity_shipped'] = $orderItem->getQuantityShipped() ?: 0;
            $itemPrice = $orderItem->getItemPrice();
            $orderItemTemp['currency'] = $itemPrice ? $itemPrice->getCurrencyCode() : null;
            $orderItemTemp['price'] =  $itemPrice ? $itemPrice->getAmount() : 0;
            $shippingPrice = $orderItem->getShippingPrice();
            $orderItemTemp['shipping_price'] = $shippingPrice  ? $shippingPrice->getAmount() : 0;
            $buyerInfo = $orderItem->getBuyerInfo();
            if($buyerInfo){
                $giftWrapPrice = $buyerInfo->getGiftWrapPrice();
                $orderItemTemp['gift_wrap_price'] =  $giftWrapPrice ? $giftWrapPrice->getAmount() : 0;
            }else{
                $orderItemTemp['gift_wrap_price'] =  0;
            }
            $shippingDiscount = $orderItem->getShippingDiscount();
            $orderItemTemp['shipping_discount'] =  $shippingDiscount ? $shippingDiscount->getAmount() : 0;
            $promotionDiscount = $orderItem->getPromotionDiscount();
            $orderItemTemp['promotion_discount'] =  $promotionDiscount ? $promotionDiscount->getAmount() : 0;
            AmazonOrderItem::query()->updateOrCreate(['order_item_id' => $orderItem->getOrderItemId()],$orderItemTemp);
            DB::connection('mysql_amazon')->commit();
        }catch (\Exception $e){
            DB::connection('mysql_amazon')->rollBack();
            Log::log('error',$e->getMessage().'Trace:'.$e->getTraceAsString());
        }
    }

    /**
     * 使用 NextToken 参数返回下一页订单商品。
     * @param $apiInstance
     * @param $accountId
     * @param $order_id
     * @param $next_token
     */
    private static function _getOrderItemsByNextToken($apiInstance,$accountId,$order_id,$next_token){
        if($next_token){
            sleep(2);
            $orderItemsList = self::_getOrderItems($apiInstance,$order_id,$next_token);
            if($orderItemsList){
                $orderItems = $orderItemsList->getOrderItems();
                foreach ($orderItems as $orderItem){
                    self::_extractAmazonOrderItems($orderItem,$order_id,$accountId);
                }
                $next_token = $orderItemsList->getNextToken();
                self::_getOrderItemsByNextToken($apiInstance,$accountId,$order_id,$next_token);
            }
        };
    }

    private static function _getOrderItems(OrdersApi $apiInstance,$order_id,$next_token = null){
        try{
            $result = $apiInstance->getOrderItems($order_id,$next_token);
        }catch (Exception $e){
            Log::log('error',$e->getMessage().'Trace:'.$e->getTraceAsString());
            return null;
        }
        return $result->getPayload();
    }

    //-------------------------------------GetOrder------------------------------------------------------------
    /**
     * 根据您指定的单个 AmazonOrderId 值返回订单。
     * @param $config
     * @param $account
     * @param $orderId
     * @return bool
     */
    public static function apiGetOrder($config,$account,$orderId){
        if(!$account)return false;
        $apiInstance = new OrdersApi($config);
        $order = self::_getOrder($apiInstance,$orderId);
        self::_extractAmazonOrder($order,$apiInstance,$account->id);
        return true;
    }

    private static function _getOrder(OrdersApi $apiInstance,$orderId){
        try{
            $result = $apiInstance->getOrder($orderId);
        }catch (Exception $e){
            Log::log('error',$e->getMessage().'Trace:'.$e->getTraceAsString());
            return null;
        }
        return $result->getPayload();
    }

    /**
     * 返回您在指定OrderIDs的订单。
     * @param $config
     * @param $account
     * @param $amazon_order_ids
     * @return false|OrdersList|null
     */
    public static function testAPIViaOrderID($config,$account,$amazon_order_ids): bool|OrdersList|null
    {
        $marketplace_ids = $account->account_country->pluck('marketplace_id')->toArray();
        $apiInstance = new OrdersApi($config);
        return self::_getOrders($apiInstance,$marketplace_ids,null,null,$amazon_order_ids);
    }
}
